#pragma once

#include "MetroClass.h"
#include "MMacros.h"

MCLASS(PVectorElement);
MGENOBJECT(PVectorElement, Value);
MGENOBJECT(PVectorElement, Next);
MENDCLASS(PVectorElement);

partial ref class PVector {
private:
	IVector<MetroClass^>^ vector;
public:
	property IVector<MetroClass^>^ Array { IVector<MetroClass^>^ get() { return vector; } }
	static PVector^ Create() { auto v = ref new PVector; v->Clear(); return v; }
	void Clear() { vector = ref new Vector<MetroClass^>; }
	void DidInit() { //OutputDebugString(L"Vector awake from store\n");
		Clear();
		if (HasObjectProperty("FirstElement")) {
			auto el = (PVectorElement^) GetObjProperty("FirstElement");
			while (el != nullptr) {
				vector->Append(el->Value);
				el = (PVectorElement^) el->Next;
			}
			RemoveObjectProperty("FirstElement");
		}
	}
	void WillStore() { //OutputDebugString(L"Vector to be stored\n");
		if (HasObjectProperty("FirstElement")) RemoveObjectProperty("FirstElement");
		int pos = 0;
		PVectorElement^ prevEl = nullptr;
		while (pos < vector->Size) {
			auto el = ref new PVectorElement;
			el->Value = vector->GetAt(pos++);
			if (prevEl != nullptr) prevEl->Next = el;
			if (!HasObjectProperty("FirstElement")) FirstElement = el;
			prevEl = el;
		}
	}
	void Add(MetroClass^ obj) { vector->Append(obj); }
	String^ Description() {
		String^ desc = "[";
		for (int i = 0; i < vector->Size; i++) {
			desc += vector->GetAt(i)->ToString();
			if (i < vector->Size - 1) desc += ", ";
		}
		return desc + "]";
	}
};

MCLASS(PVector);
MOBJECT(PVector, PVectorElement, FirstElement)
MENDCLASS(PVector);

MCLASS(PMapElement);
MSTRING(PMapElement, Key);
MGENOBJECT(PMapElement, Value);
MGENOBJECT(PMapElement, Next);
MENDCLASS(PMapElement);

partial ref class PMap {
private:
	IMap<String^,MetroClass^>^ map;
public:
	property IMap<String^,MetroClass^>^ Dictionary { IMap<String^,MetroClass^>^ get() { return map; } }
	static PMap^ Create() { auto v = ref new PMap; v->Clear(); return v; }
	void Clear() { map = ref new Map<String^,MetroClass^>; }
	void DidInit() { //OutputDebugString(L"Map awake from store\n");
		Clear();
		if (HasObjectProperty("FirstElement")) {
			auto el = (PMapElement^) GetObjProperty("FirstElement");
			while (el != nullptr) {
				map->Insert(el->Key, el->Value);
				el = (PMapElement^) el->Next;
			}
			RemoveObjectProperty("FirstElement");
		}
	}
	void WillStore() { //OutputDebugString(L"Map to be stored\n");
		if (HasObjectProperty("FirstElement")) RemoveObjectProperty("FirstElement");
		if (map->Size > 0) {
			PMapElement^ prevEl = nullptr;
			auto iter = map->First();
			do {
				auto el = ref new PMapElement;
				el->Key = iter->Current->Key;
				el->Value = iter->Current->Value;
				if (prevEl != nullptr) prevEl->Next = el;
				if (!HasObjectProperty("FirstElement")) FirstElement = el;
				prevEl = el;
			} while (iter->MoveNext());
		}
	}
	void Insert(String^ key, MetroClass^ obj) { map->Insert(key, obj); }
	String^ Description() {
		String^ desc = "[";
		if (map->Size > 0) {
			auto iter = map->First();
			do {
				MetroClass^ value = iter->Current->Value;
				desc += "(" + iter->Current->Key + "=" + value->ToString() + ")";
			} while (iter->MoveNext());
			iter = nullptr;
		}
		return desc + "]";
	}
};

MCLASS(PMap);
MOBJECT(PMap, PMapElement, FirstElement)
MENDCLASS(PMap);
